﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using com.eFORCE.CommonUtilsForSearch;

public partial class SearchInGridControl : System.Web.UI.UserControl
{
    #region Private Properties

    private string targetControlID;
    private List<string> listExcludedFields;
    List<string> lstcolumnsToSearch = new List<string>();
    private string filterCriteria;
    private string UniqueKey
    {
        get
        {
            return keyUnique.Value;
        }
        set
        {
            keyUnique.Value = value;
        }
    }
    private string SortExpressionOfTargetControl
    {
        get
        {
            string valueToReturn = null;
            switch (OriginalDataSourceStateManagementOption)
            {
                case OriginalDataSourceStateManagementOptions.UseSession:
                    valueToReturn = (string)Session[UniqueKey + "_SortExpression"];
                    break;
                case OriginalDataSourceStateManagementOptions.UseViewstate:
                    valueToReturn = (string)ViewState[UniqueKey + "_SortExpression"];
                    break;
            }
            return valueToReturn;
        }
        set
        {
            switch (OriginalDataSourceStateManagementOption)
            {
                case OriginalDataSourceStateManagementOptions.UseSession:
                    Session[UniqueKey + "_SortExpression"] = value;
                    break;
                case OriginalDataSourceStateManagementOptions.UseViewstate:
                    ViewState[UniqueKey + "_SortExpression"] = value;
                    break;
            }
        }
    }

    #endregion

    #region Public Properties


    [Browsable(true)]
    public string TargetControlID
    {
        get
        {
            if (string.IsNullOrEmpty(targetControlID))
                throw new NullReferenceException(
                    "You must bind to a control through the TargetControlId property before you use the Search Control");
            return targetControlID;
        }
        set { targetControlID = value; }
    }

    public GridView TargetControl
    {
        get
        {
            GridView gvTarget = null;
            Control cntrl = null;
            if (!string.IsNullOrEmpty(TargetControlID))
            {
                cntrl = LocateControl(this, TargetControlID);
            }
            if (cntrl != null)
            {
                gvTarget = (GridView)cntrl;
            }
            return gvTarget;
        }
    }

    [Browsable(true)]
    public string ExcludedFieldsCSV
    {
        get
        {
            string csv = "";
            foreach (string field in listExcludedFields)
            {
                csv += field + ",";
            }
            char[] charsToTrim = { ',' };
            csv.TrimEnd(charsToTrim);
            return csv;
        }
        set
        {
            listExcludedFields = value.Split(',').ToList();
        }
    }

    [Browsable(false)]
    public List<string> ExcludedFields
    {
        get
        {
            return this.listExcludedFields;
        }
        set
        {
            this.listExcludedFields = value;
        }
    }
    [Browsable(true)]
    public OriginalDataSourceStateManagementOptions OriginalDataSourceStateManagementOption
    {
        get;
        set;
    }

    [Browsable(false)]
    public object OriginalData
    {
        get
        {
            object valueToReturn = null;
            if (OriginalDataSourceStateManagementOption != OriginalDataSourceStateManagementOptions.UseNone)
            {
                if (!Page.IsPostBack)
                {
                    RetainedData = TargetControl.DataSource;
                }
                valueToReturn = RetainedData;
            }
            else
            {
                return TargetControl.DataSource;
            }
            return valueToReturn;
        }
    }

    private object RetainedData
    {
        get
        {
            object valueToReturn = null;
            switch (OriginalDataSourceStateManagementOption)
            {
                case OriginalDataSourceStateManagementOptions.UseSession:
                    valueToReturn = Session[UniqueKey + "_RetainedData"];
                    break;
                case OriginalDataSourceStateManagementOptions.UseViewstate:
                    valueToReturn = ViewState[UniqueKey + "_RetainedData"];
                    break;
            }
            return valueToReturn;
        }
        set
        {
            switch (OriginalDataSourceStateManagementOption)
            {
                case OriginalDataSourceStateManagementOptions.UseSession:
                    Session[UniqueKey + "_RetainedData"] = TargetControl.DataSource;
                    break;
                case OriginalDataSourceStateManagementOptions.UseViewstate:
                    ViewState[UniqueKey + "_RetainedData"] = TargetControl.DataSource;
                    break;
            }
        }
    }

    [Browsable(false)]
    public object FilteredData { get; set; }

    public enum OriginalDataSourceStateManagementOptions
    {
        UseSession,
        UseViewstate,
        UseNone
    }
    [Browsable(false)]
    public string SelectedColumnHeaderName
    {
        get
        {
            return ddlFilterExpression.SelectedValue;
        }

    }
    [Browsable(false)]
    public string SearchText
    {
        get
        {
            return txtFilterSearch.Text.Trim();
        }
    }
    [Browsable(false)]
    public DataView DtOriginaldata
    {
        get
        {
            DataView dvOriginal = new DataView();
            if (OriginalData != null)
            {
                dvOriginal = ConvertOriginalDataToDataView(OriginalData);
            }
            return dvOriginal;
        }
    }

    #endregion

    #region Handler Delegates

    public delegate void SearchResetEventHandler();

    #endregion

    #region Control Events

    public event SearchResetEventHandler SearchResetEvent;

    #endregion

    #region Page Events

    protected void Page_Load(object sender, EventArgs e)
    {
        TargetControl.Sorted += new EventHandler(TargetControl_Sorted);
        if (!Page.IsPostBack)
        {
            UniqueKey = Guid.NewGuid().ToString();
        }
        if (Page.IsPostBack)
        {
            foreach (ListItem li in ddlFilterExpression.Items)
            {
                if (li != ddlFilterExpression.Items[0])
                {
                    lstcolumnsToSearch.Add(li.Value);
                }
            }
        }


    }

    void TargetControl_Sorted(object sender, EventArgs e)
    {
        UpdateOriginalData();
    }

    private void AttachEventToTargetControl(EventArgs e)
    {
        gvTarget_DataBound(null, e);
    }

    public void RenderControl()
    {
        AttachEventToTargetControl(null);
        string searchTextSession = SearchText;
        string SelectedColumnHeaderNameSession = SelectedColumnHeaderName;
        if (searchTextSession != null && searchTextSession.Trim() == "")
        {
            {
                Reset();
            }
        }
        else if (!string.IsNullOrEmpty(SelectedColumnHeaderNameSession) && !string.IsNullOrEmpty(searchTextSession))
        {
            if (string.IsNullOrEmpty(hiddenValue.Value))
            {
            }
            else
            {
                SetFilterExpression(searchTextSession, SelectedColumnHeaderNameSession);
                Filter();
            }
        }
        else if (string.IsNullOrEmpty(SelectedColumnHeaderNameSession) && !string.IsNullOrEmpty(searchTextSession))
        {
            GetFilterExpressionForFreeTextSearch(searchTextSession, lstcolumnsToSearch);
            Filter();
        }
        txtFilterSearch.Text = string.IsNullOrEmpty(SearchText) ? string.Empty : SearchText;
        if (!string.IsNullOrEmpty(SelectedColumnHeaderName))
        {
            ListItem liToSelect = ddlFilterExpression.Items.FindByValue(SelectedColumnHeaderName);
            if (liToSelect != null)
                ddlFilterExpression.SelectedValue = liToSelect.Value.ToString();
        }

    }
    protected override void OnPreRender(EventArgs e)
    {
        RenderControl();
    }

    protected void gvTarget_DataBound(object sender, EventArgs e)
    {
        string strSelectedValue = ddlFilterExpression.SelectedValue;
        //TODO: remove try catch
        try
        {
            if (TargetControl.DataSource != null)
            {
                if (DtOriginaldata.Table.Rows.Count > 0)
                {
                    searchPanel.Visible = true;
                    GetSearchableColumnHeaderForTargetGrid();
                }
                else
                {
                    searchPanel.Visible = false;
                }
            }
            ddlFilterExpression.SelectedValue = string.IsNullOrEmpty(strSelectedValue) ? "Free Text Search" : strSelectedValue;
        }
        catch (Exception)
        {
            //TODO: handling
        }
    }

    protected void btnSearch_Click(object sender, EventArgs e)
    {
        hiddenValue.Value = txtFilterSearch.Text;
        RaiseSearchResetEvent();
    }

    protected void btnReset_Click(object sender, EventArgs e)
    {
        RaiseSearchResetEvent();
        Reset();
    }
    private void RaiseSearchResetEvent()
    {
        try
        {
            SearchResetEvent();
        }
        catch (Exception)
        {
            //TODO:Handle Catch
        }
    }


    #endregion

    #region Methods
    /// <summary>
    /// Method for retrieving the searchable column header for the target grid
    /// </summary>
    private void GetSearchableColumnHeaderForTargetGrid()
    {
        if (ddlFilterExpression.Items.Count.Equals(0))
        {
            Hashtable columnNames = new Hashtable();
            if (TargetControl.Columns.Count != 0)
            {
                foreach (DataControlField col in TargetControl.Columns)
                {
                    if (col != null)
                        if (!columnNames.Contains(col))
                            if (col.HeaderText != "" || col.AccessibleHeaderText != "")
                            {
                                columnNames.Add(col.HeaderText, col.AccessibleHeaderText);
                            }
                }
                Hashtable requireColumnName = (Hashtable)columnNames.Clone();
                if (listExcludedFields != null)
                {
                    foreach (string removedfield in listExcludedFields)
                    {
                        foreach (DictionaryEntry dic in columnNames)
                        {
                            if (dic.Value.ToString().Equals(removedfield))
                            {
                                requireColumnName.Remove(dic.Key);
                            }
                        }
                    }
                    foreach (DictionaryEntry dic in requireColumnName)
                        ddlFilterExpression.Items.Add(new ListItem(dic.Key.ToString(), dic.Value.ToString()));
                    ddlFilterExpression.Items.Insert(0, new ListItem("Free Text Search"));
                }
                else
                {
                    foreach (DictionaryEntry dic in columnNames)
                        ddlFilterExpression.Items.Add(new ListItem(dic.Key.ToString(), dic.Value.ToString()));
                    ddlFilterExpression.Items.Insert(0, new ListItem("Free Text Search"));
                }
            }
            else
            {
                List<string> lstForDdlFilterExp = new List<string>();
                foreach (DataColumn dc in DtOriginaldata.Table.Columns)
                {
                    for (int colCount = 1; colCount < DtOriginaldata.Table.Columns.Count; colCount++)
                    {
                        if (dc != null)
                            if (!lstForDdlFilterExp.Contains(dc.ToString()))
                                lstForDdlFilterExp.Add(dc.ToString());
                    }

                }
                foreach (string strItem in lstForDdlFilterExp)
                    ddlFilterExpression.Items.Add(strItem);
                ddlFilterExpression.Items.Insert(0, new ListItem("Free Text Search"));
            }

        }
    }
    /// <summary>
    /// Method for retrieving the filter expression
    /// </summary>
    /// <param name="dc"></param>
    /// <param name="searchText"></param>
    /// <returns>string</returns>
    private string GetFilterExpression(DataColumn dc, string searchText)
    {
        string filterExpression = "";
        if ((!dc.DataType.Equals(typeof(bool))) && (!dc.DataType.Equals(typeof(DateTime))) && (!dc.DataType.Equals(typeof(int))) && (!dc.DataType.Equals(typeof(Int64))))
        {
            try
            {
                if (!string.IsNullOrEmpty(searchText) && !searchText.Contains("*"))
                {
                    filterExpression =
                        string.Format("({0} Like '%{1}%')", dc.ColumnName,
                                      searchText.Replace('*', ' ').Replace('%', ' '));
                }
                else if (!string.IsNullOrEmpty(searchText) && searchText.EndsWith("*"))
                {
                    searchText = searchText.TrimEnd('*');
                    filterExpression = "(" + dc.ColumnName + " " + "Like " + " " + "'" + searchText + "%'" + ")";
                }
                else if (!string.IsNullOrEmpty(searchText) && searchText.StartsWith("*"))
                {
                    searchText = searchText.TrimStart('*');
                    filterExpression = "(" + dc.ColumnName + " " + "Like " + " " + "'%" + searchText + "'" + ")";
                }

                else
                {
                    filterExpression = string.Format("({0} Like '')", dc.ColumnName);

                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        else if ((dc.DataType.Equals(typeof(DateTime))))
        {
            try
            {
                if (!string.IsNullOrEmpty(searchText))
                    filterExpression = string.Format("({0} = '{1}')", dc.ColumnName,
                                  searchText.Replace('*', ' ').Replace('%', ' '));
                else
                    filterExpression = string.Format("({0} = '')", dc.ColumnName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        else if ((dc.DataType.Equals(typeof(int))))
        {
            try
            {
                if (!string.IsNullOrEmpty(searchText))
                    filterExpression =
                        string.Format("({0} = {1})", dc.ColumnName,
                                      searchText.Replace('*', ' ').Replace('%', ' '));
                else
                    filterExpression = string.Format("({0} = '')", dc.ColumnName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        else if ((dc.DataType.Equals(typeof(Int64))))
        {
            try
            {
                if (!string.IsNullOrEmpty(searchText))
                    filterExpression =
                        string.Format("({0} = {1})", dc.ColumnName,
                                      searchText.Replace('*', ' ').Replace('%', ' '));
                else
                    filterExpression = string.Format("({0} = '')", dc.ColumnName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        else
        {
            if (string.IsNullOrEmpty(searchText))
            {
                filterExpression = string.Format("({0} IS NULL)", dc.ColumnName);
                return filterExpression;
            }

            else
            {

                filterExpression = string.Format("({0} = {1})", dc.ColumnName,
                                               searchText);
            }
        }
        return filterExpression;
    }
    /// <summary>
    /// Method for setting the filter expression
    /// </summary>
    /// <param name="searchText"></param>
    /// <param name="selectedColumnHeaderName"></param>
    private void SetFilterExpression(string searchText, string selectedColumnHeaderName)
    {
        if (!ddlFilterExpression.Items.Count.Equals(0))
        {
            if (selectedColumnHeaderName != "Free Text Search")
            {
                if (DtOriginaldata != null && DtOriginaldata.Table.Rows.Count > 0)
                {
                    filterCriteria = "";
                    try
                    {
                        filterCriteria = GetFilterExpression(DtOriginaldata.Table.Columns[selectedColumnHeaderName],
                                                               searchText);
                    }
                    catch (Exception ex)
                    {
                        ShowErrorMessage();
                    }
                }
            }
            else
            {
                foreach (ListItem colHeaderName in ddlFilterExpression.Items)
                {
                    DataColumn dc = (DtOriginaldata.Table.Columns[colHeaderName.Value]);
                    if (!colHeaderName.Text.Equals(ddlFilterExpression.Items[0].Value))
                    {
                        try
                        {
                            if (dc.DataType == Type.GetType("System.Boolean"))
                                continue;

                            filterCriteria = GetFilterExpressionForFreeTextSearch(searchText, lstcolumnsToSearch);
                        }
                        catch (Exception ex)
                        {
                            ShowErrorMessage();
                        }
                    }
                    else if (colHeaderName.Text.Equals(ddlFilterExpression.Items[0].Value) && DtOriginaldata.Table.Columns.Count == 1)
                    {
                        filterCriteria = GetFilterExpressionForFreeTextSearch(searchText, lstcolumnsToSearch);
                    }
                    else if (colHeaderName.Text.Equals(ddlFilterExpression.Items[0].Value) && DtOriginaldata.Table.Columns.Count > 1)
                    {
                        filterCriteria = GetFilterExpressionForFreeTextSearch(searchText, lstcolumnsToSearch);
                    }
                }
                filterCriteria = filterCriteria.Trim();
                filterCriteria = filterCriteria.TrimEnd(new char[] { 'o', 'r' });
            }
        }
    }
    /// <summary>
    /// Method for generating the filter expression for free text search
    /// </summary>
    /// <param name="searchText"></param>
    /// <returns>string</returns>
    private string GetFilterExpressionForFreeTextSearch(string searchText, List<string> lstcolumnsToSearch)
    {
        string filter = "";
        StringBuilder strFilter = new StringBuilder();
        string strFilterText = "";
        char[] strRemove = {
                               'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
                               's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
                               'K', 'L', 'M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

        foreach (DataRow row in DtOriginaldata.Table.Rows)
        {
            int count = row.ItemArray.Count();
            for (int i = 0; i < count; i++)
            {
                if (count == 1)
                {
                    if (row.ItemArray[i].GetType().Equals(typeof(System.Int16)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.Int32)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.Int64)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.UInt16)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.UInt32)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.UInt64)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.Single)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.Decimal)) ||
                        row.ItemArray[i].GetType().Equals(typeof(System.Double)))
                    {
                        filter = "Item =" + searchText;
                    }
                    else if (row.ItemArray[i].GetType().Equals(typeof(System.String)) ||
                             row.ItemArray[i].GetType().Equals(typeof(System.Char)))
                    {
                        filter = "Item Like '%" + searchText + "%'";
                    }
                    else if (row.ItemArray[i].GetType().Equals(typeof(System.DateTime)))
                    {
                        continue;
                    }
                }
                else if (count > 1)
                {
                    foreach (string colName in lstcolumnsToSearch)
                    {
                        DataColumn col = DtOriginaldata.Table.Columns[colName];
                        if (col == null)
                        {
                            continue;
                        }
                        if (col.DataType.Equals(typeof(System.Int16)) || col.DataType.Equals(typeof(System.Int32)) || col.DataType.Equals(typeof(System.Int64)) || col.DataType.Equals(typeof(System.UInt16)) || col.DataType.Equals(typeof(System.UInt32)) || col.DataType.Equals(typeof(System.UInt64)) || col.DataType.Equals(typeof(System.Single)) || col.DataType.Equals(typeof(System.Decimal)))
                        {
                            int charCount = searchText.IndexOfAny(strRemove.ToArray<Char>());
                            if (charCount >= 0)
                                continue;
                            else
                                filter = col + " = " + searchText + " " + "or ";
                        }
                        else if (col.DataType.Equals(typeof(System.String)) ||
                             col.DataType.Equals(typeof(System.Char)))
                        {
                            filter = col + " Like '%" + searchText + "%'" + "" + "or ";
                        }
                        else if (col.DataType.Equals(typeof(System.DateTime)))
                        {
                            continue;
                        }
                        if (!strFilter.ToString().ToLower().Equals(filter))
                        {
                            strFilterText = strFilter.Append(filter).ToString();
                        }
                    }
                    return strFilterText;
                }
            }
        }
        return filter;
    }

    /// <summary>
    /// Method for filtering the grid
    /// </summary>
    private void Filter()
    {
        TargetControl.Visible = true;
        DataView dv = DtOriginaldata;
        if (dv == null || dv.Table == null)
            return;
        try
        {
            dv.RowFilter = this.filterCriteria;
            if (dv.Count <= 0)
            {
                TargetControl.DataSource = null;
                TargetControl.DataBind();
                ShowErrorMessage();
            }
            else
            {
                lblEmptyMessage.Visible = false;
                TargetControl.DataSource = dv;
                TargetControl.DataBind();
            }

        }
        catch (Exception e)
        {
            if (e.GetBaseException().Message.Equals("Syntax error: Missing operand before 'Or' operator."))
            {
            }
            else
            {
                ShowErrorMessage();
            }
        }
    }
    /// <summary>
    /// method for resetting the search in grid control
    /// </summary>
    public void Reset()
    {
        try
        {
            lblEmptyMessage.Visible = false;
            txtFilterSearch.Text = string.Empty;
            ddlFilterExpression.SelectedIndex = 0;
            TargetControl.Visible = true;
            if (OriginalData.GetType().Equals(typeof(DataView)))
            {
                DataView dv = (DataView)OriginalData;
                dv.RowFilter = "";
                if (SortExpressionOfTargetControl != null)
                    dv.Sort = SortExpressionOfTargetControl;
                dv.RowFilter = "";
                TargetControl.DataSource = dv;
            }
            else if (OriginalData.GetType().Equals(typeof(DataTable)))
            {
                DataTable dt = (DataTable)OriginalData;
                if (SortExpressionOfTargetControl != null)
                    dt.DefaultView.Sort = SortExpressionOfTargetControl;
                dt.DefaultView.RowFilter = "";
                TargetControl.DataSource = dt;
            }
            else
            {
                TargetControl.DataSource = OriginalData;
            }
            TargetControl.DataBind();
        }
        catch (Exception ex)
        {

        }
    }
    /// <summary>
    /// Recursive method for finding the child control relative to parent
    /// </summary>
    /// <param name="relativeTo"></param>
    /// <param name="sID"></param>
    /// <returns>Control</returns>
    private Control LocateControl(Control relativeTo, String sID)
    {
        Control _control;
        _control = relativeTo.FindControl(sID);
        if (_control == null && relativeTo.Parent != null)
            _control = LocateControl(relativeTo.Parent, sID);
        if (_control == null && relativeTo.Page != null)
            _control = relativeTo.Page.FindControl(sID);
        return _control;
    }
    /// <summary>
    /// method for showing the error message
    /// </summary>
    private void ShowErrorMessage()
    {
        lblEmptyMessage.Visible = true;
        TargetControl.Visible = false;
    }
    /// <summary>
    /// converts any type of original data from datasource to dataview
    /// </summary>
    /// <param name="originalData"></param>
    /// <returns>DataView</returns>
    private DataView ConvertOriginalDataToDataView(object originalData)
    {
        DataView dvOriginalDataTable;
        if (originalData.GetType().Equals(typeof(DataView)))
        {
            dvOriginalDataTable = (DataView)originalData;
        }
        else if (originalData.GetType().Equals(typeof(DataTable)))
        {
            dvOriginalDataTable = ((DataTable)originalData).DefaultView;
        }
        else
        {
            DataTable dtConverted = ReflectionUtils.ConvertToDataTable(originalData);
            dvOriginalDataTable = new DataView(dtConverted);
        }
        return dvOriginalDataTable;
    }

    /// <summary>
    /// Use this method when the original data of the grid changes
    /// </summary>
    public void UpdateOriginalData()
    {
        RetainedData = TargetControl.DataSource;
        if (RetainedData.GetType().Equals(typeof(DataView)))
        {
            SortExpressionOfTargetControl = ((DataView)RetainedData).Sort;
        }
        else if (RetainedData.GetType().Equals(typeof(DataTable)))
        {
            SortExpressionOfTargetControl = ((DataTable)RetainedData).DefaultView.Sort;
        }
    }


    #endregion

}
